import logging
import requests
import threading
import tkinter as tk
from src.websocket_app import WebSocketManager
from tkinter import ttk, scrolledtext, messagebox


class DownloadTab:

    def __init__(self, base):
        self.base = base

    def setup_cert_tab(self, parent):
        """ 下载海关客户端、 下载证书 """
        main_frame = ttk.Frame(parent)
        main_frame.pack(fill='both', expand=True, padx=10, pady=10)

        # 海关客户端下载区域
        client_frame = ttk.LabelFrame(main_frame, text="海关官方客户端下载", padding=15)
        client_frame.pack(fill='x', pady=(0, 15))
        # 客户端下载说明
        client_desc = ttk.Label(
            client_frame,
            text=f"下载并安装海关电子口岸客户端程序（{self.base.coustoms_client_name}）",
            wraplength=600
        )
        client_desc.pack(anchor='w', pady=(0, 10))

        # 客户端下载按钮和状态
        client_button_frame = ttk.Frame(client_frame)
        client_button_frame.pack(fill='x')
        self.download_client_btn = ttk.Button(
            client_button_frame,
            text="下载海关客户端",
            command=self.download_customs_client,
            width=20
        )
        self.download_client_btn.pack(side='left', padx=(0, 10))

        self.client_status_label = ttk.Label(client_button_frame, text="就绪")
        self.client_status_label.pack(side='left')

        # 客户端下载进度条
        self.client_progress = ttk.Progressbar(
            client_frame,
            mode='determinate',
            length=400
        )
        self.client_progress.pack(fill='x', pady=(10, 0))


        # 下载证书区域
        cert_frame = ttk.LabelFrame(main_frame, text="证书下载（请使用操作员卡）", padding=15)
        cert_frame.pack(fill='x', pady=(0, 15))
        cert_button_frame = ttk.Frame(cert_frame)
        cert_button_frame.pack(fill='x')
        self.download_cert_btn = ttk.Button(
            cert_button_frame,
            text="下载证书",
            command=self.download_customs_cert,
            width=20
        )
        self.download_cert_btn.pack(side='left', padx=(0, 10))

        self.cert_status_label = ttk.Label(cert_button_frame, text="等待启动客户端", foreground="red")
        self.cert_status_label.pack(side='left')
        self.cert_status_label.pack(side='left')


        # 日志显示区域
        log_frame = ttk.LabelFrame(main_frame, text="下载日志", padding=10)
        log_frame.pack(fill='both', expand=True)

        self.download_log = scrolledtext.ScrolledText(
            log_frame,
            height=8,
            wrap=tk.WORD
        )
        self.download_log.pack(fill='both', expand=True)

        # 配置日志输出到文本框
        self.setup_download_logging()

    def download_customs_client(self):
        """下载海关客户端"""
        def download_task():
            try:
                from tkinter import filedialog
                self.base.root.after(0, lambda: self.client_status_label.config(text="请选择保存路径..."))

                # 在主线程中执行文件对话框
                save_path = []
                def select_path():
                    path = filedialog.asksaveasfilename(
                        title="保存海关客户端",
                        defaultextension=".exe",
                        initialfile=self.base.coustoms_client_name,
                        filetypes=[
                            ("可执行文件", "*.exe"),
                            ("所有文件", "*.*")
                        ]
                    )
                    save_path.append(path)

                # 在主线程中执行路径选择
                self.base.root.after(0, select_path)

                # 等待路径选择完成
                import time
                timeout = 120  # 最多等待120秒
                while not save_path and timeout > 0:
                    time.sleep(0.1)
                    timeout -= 0.1

                if not save_path or not save_path[0]:
                    self.download_logger.info("用户取消下载")
                    self.base.root.after(0, lambda: self.client_status_label.config(text="用户取消"))
                    return

                local_filename = save_path[0]
                self.base.root.after(0, lambda: self.client_status_label.config(text=f"已保存到: {local_filename}"))
                # 更新UI状态
                self.base.root.after(0, lambda: self.download_client_btn.config(state='disabled'))
                self.base.root.after(0, lambda: self.client_status_label.config(text="正在获取下载链接..."))
                self.base.root.after(0, lambda: self.client_progress.config(value=10))

                self.download_logger.info("开始获取海关客户端下载链接...")
                # 从JS响应中提取下载URL
                download_url = self.base.coustoms_client_url
                if not download_url:
                    self.base.load_init_data() # 尝试重新获取
                    download_url = self.base.coustoms_client_url
                    if not download_url:
                        raise ValueError("无法提取下载链接")

                self.download_logger.info(f"获取到下载链接: {download_url}")
                self.base.root.after(0, lambda: self.client_progress.config(value=30))
                self.base.root.after(0, lambda: self.client_status_label.config(text="正在下载..."))

                # 下载文件
                local_filename = save_path[0]
                with requests.get(download_url, stream=True, timeout=60, verify=False) as r:
                    r.raise_for_status()
                    total_size = int(r.headers.get('content-length', 0))

                    with open(local_filename, 'wb') as f:
                        downloaded = 0
                        for chunk in r.iter_content(chunk_size=8192):
                            if chunk:
                                f.write(chunk)
                                downloaded += len(chunk)

                                # 更新进度条
                                if total_size > 0:
                                    progress = 30 + (downloaded / total_size) * 60
                                    self.base.root.after(0, lambda: self.client_progress.config(value=progress))

                self.base.root.after(0, lambda: self.client_progress.config(value=100))
                self.base.root.after(0, lambda: self.client_status_label.config(text="下载完成"))
                self.download_logger.info(f"海关客户端下载完成: {local_filename}")

                # 询问是否立即安装
                self.base.root.after(0, self.ask_install_client(local_filename))

            except Exception as e:
                self.download_logger.error(f"下载海关客户端失败: {e}")
                self.base.root.after(0, lambda: self.client_status_label.config(text=f"下载失败: {str(e)}"))
            finally:
                self.base.root.after(0, lambda: self.download_client_btn.config(state='normal'))

        # 在新线程中执行下载任务
        threading.Thread(target=download_task, daemon=True).start()


    def setup_download_logging(self):
        """设置下载日志输出到文本框"""
        class TextHandler(logging.Handler):
            def __init__(self, text_widget):
                super().__init__()
                self.text_widget = text_widget

            def emit(self, record):
                msg = self.format(record)
                self.text_widget.insert(tk.END, msg + '\n')
                self.text_widget.see(tk.END)

        # 创建专用的下载日志器
        self.download_logger = logging.getLogger('download')
        self.download_logger.setLevel(logging.INFO)

        # 添加文本框处理器
        text_handler = TextHandler(self.download_log)
        text_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
        self.download_logger.addHandler(text_handler)

    def ask_install_client(self, file_path):
        """询问是否立即安装客户端"""
        result = messagebox.askyesno(
            "下载完成",
            "海关客户端下载完成，是否立即安装？\n\n安装完成后请重新启动本程序。"
        )

        if result:
            try:
                import subprocess
                import os
                subprocess.Popen([file_path], shell=True)
                self.download_logger.info("已启动海关客户端安装程序")
            except Exception as e:
                self.download_logger.error(f"启动安装程序失败: {e}")
                messagebox.showerror("安装失败", f"无法启动安装程序: {e}")



    def download_customs_cert(self):
        # 先校验是否安装了客户端
        ws_manager = WebSocketManager()
        if ws_manager.is_connected_successfully(protocol="http"):
            # 获取证书编号
            def get_certno_result(args, message):
                try:
                    if not args:
                        raise ValueError("控件返回空响应")
                    if args.get("Data") and args.get("Data")[0]:
                        self.base.root.after(0, lambda: self.cert_status_label.config(
                            text="就绪 √ ",  # 把“等待安装客户端”改成“就绪”
                            foreground="black"  # 可选
                        ))
                        self.cert_no = args.get("Data")[0]
                        ws_manager2 = WebSocketManager()
                        cert_data_result = ws_manager2.sync_base_invoke("cus-sec_SpcGetSignCertAsPEM")
                        if cert_data_result.get("Data"):
                            def download_task():
                                try:
                                    from tkinter import filedialog
                                    self.base.root.after(0, lambda: self.client_status_label.config(text="请选择保存路径..."))

                                    # 在主线程中执行文件对话框
                                    save_path = []
                                    def select_path():
                                        path = filedialog.asksaveasfilename(
                                            title="保存证书",
                                            defaultextension=".cer",
                                            initialfile=self.cert_no + '.cer',
                                            filetypes=[
                                                ("可执行文件", "*.cer"),
                                                ("所有文件", "*.*")
                                            ]
                                        )
                                        save_path.append(path)

                                    # 在主线程中执行路径选择
                                    self.base.root.after(0, select_path)

                                    # 等待路径选择完成
                                    import time
                                    timeout = 120  # 最多等待120秒
                                    while not save_path and timeout > 0:
                                        time.sleep(0.1)
                                        timeout -= 0.1

                                    if not save_path or not save_path[0]:
                                        self.download_logger.info("用户取消下载")
                                        self.base.root.after(0, lambda: self.cert_status_label.config(text="用户取消"))
                                        return

                                    local_filename = save_path[0]
                                    self.base.root.after(0, lambda: self.cert_status_label.config(text=f"保存到: {local_filename}"))
                                    # 更新UI状态
                                    self.base.root.after(0, lambda: self.download_client_btn.config(state='disabled'))

                                    # 下载文件
                                    with open(local_filename, 'wb') as f:
                                        f.write(cert_data_result.get('Data')[0].encode('utf-8'))

                                    self.download_logger.info(f"证书下载完成: {local_filename}")
                                except Exception as e:
                                    self.download_logger.error(f"下载证书失败: {e}")
                                    self.base.root.after(0, lambda: self.cert_status_label.config(text=f"下载失败: {str(e)}"))
                                finally:
                                    self.base.root.after(0, lambda: self.download_cert_btn.config(state='normal'))

                                # 在新线程中执行下载任务
                            threading.Thread(target=download_task, daemon=True).start()
                        else:
                            self.download_logger.error("获取证书异常：" + message)
                    else:
                        self.download_logger.error("获取证书编号异常：" + message)
                        self.download_logger.error("请先插入操作员卡")
                        self.base.root.after(0, lambda: self.cert_status_label.config(
                            text="请先插入操作员卡",
                            foreground="red"  # 可选
                        ))
                except Exception as e:
                    self.download_logger.error("获取证书编号异常：" + str(e))
            ws_manager.base_invoke(
                method="cus-sec_SpcGetCertNo",
                args={},
                callback=get_certno_result
            )
        else:
            # 提示先安装客户端
            self.base.root.after(0, lambda: messagebox.showerror(
                "未安装",
                "请先安装并启动海关客户端"
            ))